/***************************************************************************
 * $Id : ast_main.cpp  2011/08/01 00:00:00
 *
 *       swhors@naver.com
 ***************************************************************************/

/***************************************************************************
 * history
 *
 * 2011/08/25 10:34  - initiated commentation.
 ***************************************************************************/

#include "config.h"
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <netinet/in.h>

#include <pthread.h>

#include <signal.h>
#include <fcntl.h>

#include <unistd.h>
#include <pwd.h>
#include <sys/stat.h>

using namespace std;

#include "err_msg.h"
#include "nor_msg.h"
#include "constant.h"
#include "ast_main.h"
#include "ast_db.h"
#include "ast_util.h"
#include "acd_svr.h"
#include "acd_manager.h"

#include "skylistener.h"
#include "SkyConf.h"
#include "SkyConfUtil.h"

pthread_t acd_manager_hd;

static int gAcdOperate=0;

char    gOutgoingFolder[256];
char    gCallListFolder[256];
char    gAstUserName[USERNAME_MAX_LEN];

int	gCounsellorReadyTime; // value in minute.

#ifdef _TEST_AM_MAIN
int    gRunProcess;
int    gConnected;
int    gIsConnected2DB;
#else
extern int gRunProcess;
extern int gConnected;
extern int gIsConnected2DB;
#endif

vector<ACDUSER> gAcdList;

int init_acd_manager( char * aOutgoingFolderPtr,
                      char * aListFolderPtr,
                      char * aAstUserNamePtr,
                       int   aCounsellorReadyTime )
{
    int result = 0;

    memset( gAstUserName, 0, ( sizeof(char) * USERNAME_MAX_LEN ) );
    memset( gOutgoingFolder, 0, ( sizeof(char) * 256) );

    snprintf( gOutgoingFolder,256, "%s", aOutgoingFolderPtr );
    snprintf( gCallListFolder,256, "%s", aListFolderPtr );
    snprintf( gAstUserName, USERNAME_MAX_LEN, "%s", aAstUserNamePtr );

    gCounsellorReadyTime = aCounsellorReadyTime;

    gAcdList.clear();

    result = pthread_create( &acd_manager_hd,
            NULL,
            acd_manager,
            NULL );
    if( result)
    {
        log_message( (char*)"ERROR : %s [create manager thread]\n", __FUNCTION__ );
        return -1;
    }
    return 0;
}

void run_acd_manager()
{
    gAcdOperate = 1;
    log_message( (char*)"%s", "INFO : RUN ACD MANAGER\n" );
}

void stop_acd_manager()
{
    gAcdOperate = 0;
    log_message( (char*)"%s", "INFO : STOP ACD MANAGER\n" );
}

/*************************************************************
 * kick out member
 *
 * @param [in] aMemberNumPtr - Member call number for kicking
 *
 * return  - void -
 *
 *************************************************************/
void kick_member( char *aMemberNumPtr )
{
    char sChannelBuf[ACD_MEMBER_NAME_LEN] = {0,};
    int  sChannelLen                      = ACD_MEMBER_NAME_LEN;

    if( aMemberNumPtr != NULL )
    {

        online_sql_get_channel_by_callid( aMemberNumPtr,
                sChannelBuf,
                &sChannelLen );

        if( sChannelLen > 0 )
        {
            log_message( (char*)"INFO : Kick-out %s [%s]\n",
                    aMemberNumPtr,
                    __FUNCTION__ );
#ifndef _TEST_AM_MAIN
            sendCommand( (char*)"Action: Command\r\n"\
                "Command: conference kickchannel %s\r\n\r\n",
                (char*)sChannelBuf );
#endif // _TEST_AM_MAIN
        }
        else
        {
            log_message( (char*)"WRN : Have not %s [%s]\n",
                    (char*)aMemberNumPtr,
                    __FUNCTION__ );
            /* do nothing */
        }
    }
    else
    {
        /* do nothing */
        log_message( (char*)"WRN : Member is null. [%s]\n",
                __FUNCTION__ );
    }
}

/*************************************************************
 * call to customer
 * 
 * @param [in] aCustomerNumPtr - Customer Call Number
 *               [number]:[system number]
 * 
 * return : success[1], fail[0]
 *************************************************************/
int add_customer( char *aCustomerNumPtr)
{
    int  sRetVal         = 0;
    int  sCustomerNumLen = 0;

    char *sCustomerNumEndPtr = NULL;
    char *sSystemNumberPtr   = NULL;

    char sCustomerNumBuf[ACD_MEMBER_NAME_LEN] = {0,};

    if( aCustomerNumPtr != NULL )
    {
        sCustomerNumLen = strlen( aCustomerNumPtr );

        remove_newline( aCustomerNumPtr ,sCustomerNumLen );

        sCustomerNumLen = strlen( aCustomerNumPtr );

        sCustomerNumEndPtr = aCustomerNumPtr + sCustomerNumLen;

        sSystemNumberPtr = strstr( aCustomerNumPtr , ":" );

        if( sSystemNumberPtr != NULL )
        {
            if( sSystemNumberPtr != sCustomerNumEndPtr )
            {
                memcpy( sCustomerNumBuf,
                        aCustomerNumPtr,
                        ( sSystemNumberPtr - aCustomerNumPtr ) );

                sSystemNumberPtr = sSystemNumberPtr + 1;

                generate_customer_call_withoutid( sCustomerNumBuf,
                    sSystemNumberPtr );

                sRetVal = 1;
            }
            else
            {
                /* do nothing */
                log_message( ERR_ILLEGAL_MSG, __FUNCTION__, __LINE__, 1 );
            }
        }
        else
        {
            /* do nothing */
            log_message( ERR_ILLEGAL_MSG, __FUNCTION__, __LINE__, 2 );
        }
    }
    else
    {
        /* do nothing */
        log_message( ERR_ILLEGAL_MSG, __FUNCTION__, __LINE__, 3 );
    }

    return sRetVal;
}

/*************************************************************
 * add councellor
 * 
 * @param [in] aMemberInfoPtr - member information
 *               [member number]:[member id]:[system number]
 * 
 * return : success[1], fail[0]
 *************************************************************/
int add_member( char *aMemberInfoPtr )
{
    int    sRetVal                            = 0;
    int    sMemberInfoLen                     = 0;

    char * sMemberInfoEndPtr                  = NULL;
    char * sSystemNumberPtr                   = NULL;
    char * sMemberIdPtr                       = NULL;

    char   sMemberIdBuf[ACD_MEMBER_NAME_LEN]  = {0,};
    char   sMemberNumBuf[ACD_MEMBER_NAME_LEN] = {0,};

    if( aMemberInfoPtr != NULL )
    {
        sMemberInfoLen = strlen( aMemberInfoPtr );

        remove_newline( aMemberInfoPtr ,sMemberInfoLen );

        sMemberInfoLen = strlen( aMemberInfoPtr );

        sMemberInfoEndPtr = aMemberInfoPtr + sMemberInfoLen;

        sMemberIdPtr = strstr( aMemberInfoPtr , ":" );

        if( sMemberIdPtr != NULL )
        {
            if( sMemberIdPtr != sMemberInfoEndPtr )
            {
                memcpy( sMemberNumBuf,
                        aMemberInfoPtr,
                        ( sMemberIdPtr - aMemberInfoPtr ) );
                sMemberIdPtr = sMemberIdPtr + 1;

                sSystemNumberPtr = strstr( sMemberIdPtr, ":" );

                if( sSystemNumberPtr != NULL )
                {
                    if( sMemberIdPtr != sMemberInfoEndPtr )
                    {
                        memcpy( sMemberIdBuf,
                                sMemberIdPtr,
                                ( sSystemNumberPtr - sMemberIdPtr ) );
                        sSystemNumberPtr = sSystemNumberPtr + 1;
                        generate_member_call( sMemberNumBuf,
                            sMemberIdBuf,
                            sSystemNumberPtr );
                        sRetVal = 1;
                    }
                    else
                    {
                        /* do nothing */
                        log_message( (char*)"[%s %d] ERROR : Illegal Request [1]\n",
                                __FUNCTION__,
                                __LINE__ );
                    }
                }
                else
                {
                    /* do nothing */
                    log_message( (char*)"[%s %d] ERROR : Illegal Request [1]\n",
                            __FUNCTION__,
                            __LINE__ );
                }
            }
            else
            {
                /* do nothing */
                log_message( (char*)"[%s %d] ERROR : Illegal Request [1]\n",
                        __FUNCTION__,
                        __LINE__ );
            }
        }
        else
        {
            /* do nothing */
            log_message((char*)"[%s %d] ERROR : Illegal Request [1]\n",
                    __FUNCTION__,
                    __LINE__ );
        }
    }
    else
    {
        /* do nothing */
        log_message((char*)"[%s %d] ERROR : Illegal Request [1]\n",
                __FUNCTION__,
                __LINE__ );
    }

    return sRetVal;
}

int add_acd_list( char *aFilename )
{
    char   sFilePath[256] = { 0, };
    FILE * sFilePtr       = NULL;

    sprintf( sFilePath, "%s/%s", gCallListFolder, aFilename );

    sFilePtr = fopen( sFilePath, "r" );

    if( sFilePtr )
    {
        char * sRbuffPtr  = NULL;
        char   sRbuff[64] = { 0, };

        sRbuffPtr = fgets( sRbuff, 64, sFilePtr );

        while( sRbuffPtr )
        {
            char *s = strstr( sRbuff, "\n" );
            if( s )
            {
                *s = 0;
            }
            s = strstr( sRbuff, "\r" );
            if( s )
            {
                *s = 0;
            }
            stringstream ss ( stringstream::in|stringstream::out );
            ss << sRbuff;
            ACDUSER *au = new ACDUSER();
            ss >> au->mStrCalleeID;
            ss >> au->mStrCallerID;
            gAcdList.push_back( *au );
            sRbuffPtr = fgets( sRbuff, 64, sFilePtr );
        }
        fclose( sFilePtr );
        return 1;
    }
    else
    {
        log_message( ERR_FILE_OPEN, 
                     __FUNCTION__,
                     __LINE__,
                     sFilePath );
    }
    return 0;
}

void generate_member_call( char *aOutNumPtr,
                           char *aConfNumPtr,
                           char *aOutIDPtr )
{
    generate_call( aOutNumPtr,
                   aConfNumPtr,
                   aOutIDPtr,
                   NULL );
}

void generate_customer_call_withoutid( char *aOutNumPtr,
                                       char *aConfNumPtr )
{
    char sOutIDBuf[ USERNAME_MAX_LEN ];

    memset( sOutIDBuf, 0, sizeof(char) * USERNAME_MAX_LEN );

    generate_customer_call( aOutNumPtr,
                            aConfNumPtr,
                            sOutIDBuf );
}

void generate_customer_call_withid( char *aOutNumPtr,
                                    char *aConfNumPtr,
                                    char *aOutIDPtr )
{
    generate_customer_call( aOutNumPtr,
                            aConfNumPtr,
                            aOutIDPtr );
}

void generate_customer_call( char *aOutNumPtr,
                             char *aConfNumPtr,
                             char *aOutIDPtr )
{
    char sChanName[ USERNAME_MAX_LEN ];

    memset( sChanName,
            0,
            sizeof(char) * USERNAME_MAX_LEN );

#ifndef _TEST_AM_MAIN
    GetConfOutChanName( sChanName, USERNAME_MAX_LEN );
#else /* _TEST_AM_MAIN */
    snprintf( sChanName, USERNAME_MAX_LEN, "%s", DEFAULT_CHANNAME );
#endif /* _TEST_AM_MAIN */

    generate_call( aOutNumPtr,
                   aConfNumPtr,
                   aOutIDPtr,
                   sChanName );
}

void generate_call( char *aOutNumPtr,
                    char *aConfNumPtr,
                    char *aOutIDPtr,
                    char *aChanName )
{
    char   sOutFileBuf[256] = { 0, };
    char   sTmpPathBuf[256] = { 0, };
    FILE * sFilePtr         = NULL;
    struct passwd *sAstUser = NULL;

    memset( &sOutFileBuf,
            0,
            ( sizeof(char) * 256 ) );
    memset( &sTmpPathBuf,
            0,
            ( sizeof(char) * 256 ) );

    snprintf( sOutFileBuf,
              256,
              "%s/%s.call",
              gOutgoingFolder,
              aConfNumPtr );
    snprintf( sTmpPathBuf,
              256,
              "/tmp/%s.call",
              aConfNumPtr );

    log_message( (char*)"[%s %d] %s\n",
                 __FUNCTION__,
                 __LINE__,
                 gOutgoingFolder );

    sFilePtr = fopen( sTmpPathBuf, "wt" );

    if( sFilePtr )
    {
        fprintf( sFilePtr,
                 "Channel: SIP/%s%s%s\n"\
                 "Callerid: %s<%s>\n"\
                 "Context: customer-call\n"\
                 "Extension: %s\n"\
                 "Priority: 1\n"\
                 "AlwaysDelete: Yes\n"\
                 "MaxRetries: 0\n",
                 ( aChanName!=NULL?aChanName:"" ),
                 ( aChanName!=NULL?"/":"" ),
                 aOutNumPtr,
                 aOutIDPtr,
                 aOutIDPtr,
                 aConfNumPtr );

        fclose( sFilePtr );

        sAstUser = getpwnam( gAstUserName );

        if( sAstUser )
        {
            int sRet = chown( sTmpPathBuf,
                              sAstUser->pw_uid,
                              sAstUser->pw_gid );
            if( sRet == 0 )
            {
                /* do nothing */
            }
            else
            {
                log_message( ERR_CHOWN, __FUNCTION__, __LINE__ );
            }
        }
        else
        {
            /* do nothing */
        }
        (void)chmod( sTmpPathBuf , 0766 );
        (void)rename( sTmpPathBuf, sOutFileBuf );
    }
    else
    {
        log_message( ERR_MAKE_FILE, __FUNCTION__, aOutNumPtr );
    }
}

void *acd_manager( void * aArg )
{
    char                      sConfNum[200][64];

    int                       sDbCount = 200;
    int                       sCnt     = 0;
    vector<ACDUSER>::iterator sMemberItr;

    log_message( INFO_MSG1, "Start", __FUNCTION__ );

    while( ( gRunProcess && gIsConnected2DB ) == 1)
    {
        if( gAcdOperate )
        {
            online_sql_get_counsellorlist( 0,
                                           gCounsellorReadyTime,
                                           sConfNum,
                                           &sDbCount);

            for( sCnt = 0 ; sCnt < sDbCount ; sCnt++ )
            {
                if( gAcdOperate )
                {
                    log_message( INFO_MSG3, "Wait", __FUNCTION__, __LINE__ );
                    sMemberItr = gAcdList.begin();

                    if( sMemberItr != gAcdList.end() )
                    {
                        generate_customer_call_withid( (*sMemberItr).mStrCalleeID,
                                                       sConfNum[sCnt],
                                                       (*sMemberItr).mStrCallerID );

                        log_message( INFO_MSG2,
                                     (*sMemberItr).mStrCalleeID,
                                     (*sMemberItr).mStrCallerID );

                        gAcdList.erase( sMemberItr );
                    }
                }
            }
        }
        Sleep(100);
    }
    log_message( INFO_MSG1, "End", __FUNCTION__ );
    return NULL;
}

#ifdef _TEST_AM_MAIN

void sig_handler( int aSig )
{
    if( aSig == SIGTERM || aSig == SIGKILL )
    {
        printf( "[%s %d] received signal. [%d]\n",
                __FUNCTION__,
                __LINE__,
                aSig );
        gRunProcess=0;
        gConnected=0;
        Sleep( 600 );
        if( gIsConnected2DB != 0 )
        {
            online_sql_disconnect();
        }
        exit( 0 );
    }
}

int main( int aArgc, char **aArgv )
{
    fd_set           sReadFd;
    struct timeval   sTV;
    int              sRetVal;
    REQUESTSOCK    * sSockInfo = NULL;

    if( aArgc == 4)
    {
        gIsConnected2DB = online_sql_connect();
        if( gIsConnected2DB != 0 )
        {
            signal( SIGKILL, sig_handler );
            signal( SIGTERM, sig_handler );

            gRunProcess=1;
            gConnected=1;
            init_acd_manager( aArgv[1], aArgv[2], aArgv[3], 3 );
#ifdef _DEBUG
            printf("[%s %d]\n", __FUNCTION__, __LINE__ );
#endif //_DEBUG
            sleep(60);

            /* wait up to five seconds.*/
            sTV.tv_sec  = 0;
            sTV.tv_usec = 5000;
            FD_ZERO( &sReadFd );
            printf("[%s %d] command prompt:\n", __FUNCTION__, __LINE__ );

            // read user input
            while( 1 )
            {
                FD_SET( 0, &sReadFd );
                sRetVal = select( 1, &sReadFd, NULL, NULL, &sTV );
                if( sRetVal == -1 )
                {
                    perror("select()" );
                }
                else if( sRetVal )
                {
                    sSockInfo = new REQUESTSOCK();
                    if( sSockInfo )
                    {
                        memset( sSockInfo, 0, sizeof( REQUESTSOCK ) );
                        sSockInfo->mAcptSockfd = 0;
                        int nRet = pthread_create( &sSockInfo->mThreadId,
                                                   NULL,
                                                   acdsvr_process,
                                                   sSockInfo );
                        if( nRet )
                        {
#ifdef _DEBUG
                            printf("[%s %d] ERROR \n", __FUNCTION__, __LINE__ );
#endif //_DEBUG
                            delete sSockInfo;
                        }
                        else
                        {
                            /* do nothing*/
                        }
                    }
                }
                else
                {
                    //printf("No data within five seconds.\n" );
                    /* time out..     */
                    /* nothing done.. */
                }
            }
#ifdef _DEBUG
            printf("[%s %d]\n", __FUNCTION__, __LINE__ );
#endif //_DEBUG
            gRunProcess = 0;
            gConnected  = 0;
            Sleep( 600 );
            online_sql_disconnect();
#ifdef _DEBUG
            printf("[%s %d]\n", __FUNCTION__, __LINE__ );
#endif //_DEBUG
        }
        else
        {
            printf("[%s %d]\n", __FUNCTION__, __LINE__ );
        }
    }
    else
    {
        printf( "usage : \n"\
                "       %s [folder name] [in file name] [ast user name]\n",
                aArgv[0] );
    }
}
#endif // _TEST_AM_MAIN
